package com.raycloud.robot.filter;

import java.util.HashSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.HashMap;
import com.alibaba.dubbo.rpc.RpcException;
import java.util.Iterator;
import org.apache.commons.lang3.StringUtils;
import java.util.UUID;
import java.util.Objects;
import com.alibaba.dubbo.rpc.RpcContext;
import java.util.Collection;
import org.springframework.util.CollectionUtils;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.ttl.TransmittableThreadLocal;
import java.util.Set;
import java.util.Map;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.Filter;

@Activate(group= { "consumer","provider" })
public class ChangeStatusFilter implements Filter{
    private static Map<String,Map<String,String>> cache;
    private static Set<String> tags;
    private static final ThreadLocal<String> local;
    private static final TransmittableThreadLocal<String> TTL_LOCAL;
    @Override
    public Result invoke(final Invoker<?> invoker,final Invocation invocation) throws RpcException{
        if(CollectionUtils.isEmpty(ChangeStatusFilter.tags)){
            return invoker.invoke(invocation);
        }
        final boolean providerSide=RpcContext.getContext().isProviderSide();
        String logTraceId="";
        try{
            if(providerSide){
                final Map<String,String> resultMap=this.filterTagMap(invocation);
                if(Objects.isNull(resultMap)||resultMap.isEmpty()){
                    return invoker.invoke(invocation);
                }
                final String str=UUID.randomUUID().toString();
                ChangeStatusFilter.local.set(str);
                ChangeStatusFilter.TTL_LOCAL.set((Object)str);
                ChangeStatusFilter.cache.putIfAbsent(str,resultMap);
            }
            logTraceId=ChangeStatusFilter.local.get();
            if(StringUtils.isBlank(logTraceId)){
                logTraceId=(String)ChangeStatusFilter.TTL_LOCAL.get();
            }
            if(StringUtils.isBlank(logTraceId)){
                return invoker.invoke(invocation);
            }
            final Map<String,String> resultMap=ChangeStatusFilter.cache.get(logTraceId);
            if(Objects.isNull(resultMap)||resultMap.isEmpty()){
                return invoker.invoke(invocation);
            }
            for(final String tag : ChangeStatusFilter.tags){
                if(!resultMap.containsKey(tag)){
                    continue;
                }
                RpcContext.getContext().setAttachment(tag,resultMap.get(tag));
            }
            return invoker.invoke(invocation);
        }
        finally{
            if(providerSide&&StringUtils.isNotBlank(logTraceId)){
                ChangeStatusFilter.cache.remove(logTraceId);
                ChangeStatusFilter.TTL_LOCAL.remove();
            }
            ChangeStatusFilter.local.remove();
        }
    }
    private Map<String,String> filterTagMap(final Invocation invocation){
        final Map<String,String> resultMap=new HashMap<String,String>();
        for(final String tag : ChangeStatusFilter.tags){
            final String result=invocation.getAttachment(tag);
            if(StringUtils.isBlank(result)){
                continue;
            }
            resultMap.put(tag,result);
        }
        return resultMap;
    }
    static{
        ChangeStatusFilter.cache=(Map<String,Map<String,String>>)Maps.newConcurrentMap();
        ChangeStatusFilter.tags=new HashSet<String>(Lists.newArrayList("orderStatus","returnedStatus","applyTime","logisticsStatus","itemVersion","orderStatusType","autoModel","specialServiceType","specialServiceId","preSaleStatus"));
        final String changeTags=System.getProperty("change_tag");
        if(StringUtils.isNotBlank(changeTags)){
            final String[] split;
            final String[] splitTags=split=changeTags.split(",");
            for(final String splitTag : split){
                ChangeStatusFilter.tags.add(splitTag);
            }
        }
        local=new InheritableThreadLocal<String>();
        TTL_LOCAL=new TransmittableThreadLocal();
    }
}
